
#include "at45db.h"
#include "flash.h"
#include "app_util_platform.h"
#include "nrf_gpio.h"
#include "string.h"

volatile struct meta_block meta_info;
volatile struct data_block data_double_buffer[2];

uint32_t flash_init_ctx(struct flash_ctx_t *ctx, uint8_t spi_instance) {

    uint32_t ret = 0;
    ctx->spi = (nrf_drv_spi_t *)&spi;
    nrf_gpio_cfg_output(SPI_CS_PIN);
    ret = at45db_spi_init(ctx->spi);
    return ret;
}

uint32_t flash_get_id(struct flash_ctx_t *ctx) {
    return at45db_read_flash_id(ctx->spi);
}

// send two bytes to write buffer 1
// reve tow bytes from read buffer 1
uint32_t flash_test(struct flash_ctx_t *ctx) {
    at45db_write_buffer1(ctx->spi);
    at45db_read_buffer1(ctx->spi);
    return 0;
}

uint32_t flash_read_page(struct flash_ctx_t *ctx,
                            int32_t page_id,
                            uint8_t *data, uint32_t len) {

    memset(data, 0, len);
    at45db_memory_page_read(ctx->spi, page_id, data, len);
    return 0;
}

uint32_t flash_write_page(struct flash_ctx_t *ctx,
                            int32_t page_id,
                            uint8_t *data, uint32_t len) {

    at45db_memory_page_write_through_buffer1(ctx->spi, page_id, data, len);
    return 0;
}

void flash_erase_chip(struct flash_ctx_t *ctx) {
    at45db_erase_chip(ctx->spi);
    while(flash_check_busy(ctx));
}

uint8_t flash_check_busy(struct flash_ctx_t *ctx) {
    uint8_t status = at45db_read_status(ctx->spi);
    return !(status & 0x80);    // low->busy, high -> not busy
}

void init_meta_info(struct meta_block *meta) {
    meta->magic = HEADER_MAGIC;
    meta->nrf_device_id = 0;
    meta->meta_block_id = META_BLOCK_ID;
    meta->data_block_start_id = DATA_BLOCK_START_ID;
    meta->data_block_curr_id = meta->data_block_start_id;
    meta->data_block_total_count = TOTAL_BLOCK_NUM;
    meta->adc_buffer_id = 0;
    meta->flash_buffer_id = -1;
}

struct data_block *get_curr_data_block() {
    int8_t adc_buffer_id = meta_info.adc_buffer_id;
    if(adc_buffer_id != 0 && adc_buffer_id != 1) {        // error, tmp solution
        meta_info.adc_buffer_id = 0;
        meta_info.flash_buffer_id = -1;
    }

    return &data_double_buffer[meta_info.adc_buffer_id];
}

void change_adc_buffer_id() {

    int8_t adc_buffer_id = meta_info.adc_buffer_id;
    if(adc_buffer_id == 0) {
        meta_info.adc_buffer_id = 1;
    } else {
        meta_info.adc_buffer_id = 0;
    }
    meta_info.flash_buffer_id = adc_buffer_id;
}

void flash_init_data_info(struct data_block *block, uint32_t ts, uint8_t interval) {
    block->magic = SECTOR_MAGIC;
    block->timestamp = ts; // XXX now
    block->interval = interval; // XXX maybe 1 5 10 30
    block->idx = 0;
    block->cnt = 0;
}

uint32_t flash_init_meta_info(struct flash_ctx_t *ctx, uint8_t *buf, uint32_t len) {

    flash_read_page(ctx, META_BLOCK_ID, buf, len);

    struct meta_block *meta = (struct meta_block *)buf;
    printf("%X %d %d %d %d\n", meta->magic, meta->meta_block_id,
            meta->data_block_start_id, meta->data_block_curr_id,
            meta->data_block_total_count);
    if(meta->magic == HEADER_MAGIC) {
        if(meta->data_block_curr_id > META_BLOCK_ID &&
                meta->data_block_curr_id <= TOTAL_BLOCK_NUM) {
            meta->adc_buffer_id = 0;
            return 0;
        }
    }

    init_meta_info(&meta_info);
    return 0;
}
